﻿using EMall.Application;
using EMall.IdentityService.Roles;
using EMall.Query;
using EMall.Uow;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using System.Linq;

namespace EMall.IdentityService.Users
{
    public class UserAppService : ApplicationService, IUserAppService
    {
        private readonly UserManager<User> _userManager;
        private readonly RoleManager<Role> _roleManager;
        public UserAppService(
            UserManager<User> userManager,
            RoleManager<Role> roleManager)
        {
            _userManager = userManager;
            _roleManager = roleManager;
        }
        [UnitOfWork]
        public async Task CreateAsync(CreateUserDto input)
        {
            var user = new User(input.UserName, input.Enabled, input.Name, input.Avatar, input.Email, input.PhoneNumber);
            await _userManager.CreateAsync(user, input.Password);
            await _userManager.AddToRolesAsync(user, input.Roles.Split(','));
        }
        [UnitOfWork]
        public async Task UpdateAsync(UpdateUserDto input)
        {
            var user = await _userManager.FindByIdAsync(input.Id.ToString());
            user.Update(input.Enabled, input.Name, input.Avatar, input.Email, input.PhoneNumber);
            await _userManager.UpdateAsync(user);
            var exsitingRoles = await _userManager.GetRolesAsync(user);
            var newRoles = input.Roles.Split(',');
            await _userManager.RemoveFromRolesAsync(user, exsitingRoles.Except(newRoles));
            await _userManager.AddToRolesAsync(user, newRoles.Except(exsitingRoles));
        }
        [UnitOfWork]
        public async Task DeleteAsync(DeleteUserDto input)
        {
            var user = await _userManager.FindByIdAsync(input.Id.ToString());
            await _userManager.DeleteAsync(user);
        }
        public async Task<UserDto> GetAsync(int id)
        {
            var user = await _userManager.FindByIdAsync(id.ToString());
            var result = Mapper.Map<UserDto>(user);
            result.Roles = (await _userManager.GetRolesAsync(user)).ToList();
            return result;
        }
        public async Task<IEnumerable<UserListDto>> GetListAsync(GetUserListQueryDto input)
        {
            var data = await _userManager.Users
               .Sorting(input.Sorting)
               .ToListAsync();
            var result = Mapper.Map<List<User>, List<UserListDto>>(data);

            var userRoleIds = await QueryService.GetQueryable<IdentityUserRole<int>>().Where(o => result.Select(u => u.Id).Contains(o.UserId)).Select(o => new { o.UserId, o.RoleId }).ToListAsync();
            var roles = await _roleManager.Roles.Where(o => userRoleIds.Select(ur => ur.RoleId).Contains(o.Id)).ToListAsync();
            foreach (var user in result)
            {
                var roleIds = userRoleIds.Where(ur => ur.UserId == user.Id).Select(o => o.RoleId);
                user.Roles = roles.Where(o => roleIds.Contains(o.Id)).Select(o => o.Name).ToList();
            }
            return result;
        }
        public async Task<IPagedList<UserListDto>> GetPagedListAsync(GetUserListPagingAndSortingQueryDto input)
        {
            var data = await _userManager.Users
               .Sorting(input.Sorting)
               .ToPagedListAsync(input.PageIndex, input.PageSize);
            var result = Mapper.Map<User, UserListDto>(data);

            var userRoleIds = await QueryService.GetQueryable<IdentityUserRole<int>>().Where(o => result.Items.Select(u => u.Id).Contains(o.UserId)).Select(o => new { o.UserId, o.RoleId }).ToListAsync();
            var roles = await _roleManager.Roles.Where(o => userRoleIds.Select(ur => ur.RoleId).Contains(o.Id)).ToListAsync();
            foreach (var user in result.Items)
            {
                var roleIds = userRoleIds.Where(ur => ur.UserId == user.Id).Select(o => o.RoleId);
                user.Roles = roles.Where(o => roleIds.Contains(o.Id)).Select(o => o.Name).ToList();
            }
            return result;
        }
    }
}